﻿using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using NUnit.Framework;

namespace CodeContrib.Tests
{
	public class XmlSchemaExtensionsTests
	{
		private readonly Assembly _executingAssembly;

		public XmlSchemaExtensionsTests()
		{
			_executingAssembly = Assembly.GetExecutingAssembly();
		}

		private Company GetCompany()
		{
			var companyId = Guid.Empty;

			var company = new Company
				              {
					              Id = companyId,
					              Name = "Test",
					              Uri = string.Format("http://api.test.com/company/{0}", companyId)
				              };

			for (var employeeIndex = 0; employeeIndex < 1; employeeIndex++)
			{
				var employeeId = Guid.Empty;

				var employee = new Employee
					               {
						               Id = employeeId,
						               DateOfBirth = DateTime.MinValue,
						               Uri = string.Format("http://api.test.com/employee/{0}", employeeId)
					               };

				company.Employees.Add(employee);
			}

			return company;
		}

		[Test]
		[ExpectedException(typeof (FileNotFoundException))]
		public void GetEmbeddedSchema_With_Executing_Assembly_And_Empty_SchemaPath_ShouldThrow_FileNotFoundException()
		{
			// Act
			_executingAssembly.GetEmbeddedSchema(string.Empty);
		}

		[Test]
		[ExpectedException(typeof (FileNotFoundException))]
		public void GetEmbeddedSchema_With_Executing_Assembly_And_Invalid_SchemaPath_ShouldThrow_FileNotFoundException()
		{
			// Act
			_executingAssembly.GetEmbeddedSchema("Test2.xsd");
		}

		[Test]
		[ExpectedException(typeof (FileNotFoundException))]
		public void GetEmbeddedSchema_With_Executing_Assembly_And_Null_SchemaPath_ShouldThrow_FileNotFoundException()
		{
			// Act
			_executingAssembly.GetEmbeddedSchema(null);
		}

		[Test]
		public void GetEmbeddedSchema_With_Executing_Assembly_And_Valid_SchemaPath_ShouldReturn_Single_Schema()
		{
			// Act
			var schema = _executingAssembly.GetEmbeddedSchema("Test.xsd");

			// Assert
			Assert.IsNotNull(schema);
		}

		[Test]
		[ExpectedException(typeof (ArgumentNullException))]
		public void GetEmbeddedSchema_With_Null_Assembly_And_Empty_SchemaPath_ShouldThrow_ArgumentNullException()
		{
			// Act
			XmlSchemaExtensions.GetEmbeddedSchema(null, string.Empty);
		}

		[Test]
		[ExpectedException(typeof (ArgumentNullException))]
		public void GetEmbeddedSchema_With_Null_Assembly_And_Invalid_SchemaPath_ShouldThrow_ArgumentNullException()
		{
			// Act
			XmlSchemaExtensions.GetEmbeddedSchema(null, "Test2.xsd");
		}

		[Test]
		[ExpectedException(typeof (ArgumentNullException))]
		public void GetEmbeddedSchema_With_Null_Assembly_And_Null_SchemaPath_ShouldThrow_ArgumentNullException()
		{
			// Act
			XmlSchemaExtensions.GetEmbeddedSchema(null, null);
		}

		[Test]
		[ExpectedException(typeof (ArgumentNullException))]
		public void GetEmbeddedSchema_With_Null_Assembly_And_Valid_SchemaPath_ShouldThrow_ArgumentNullException()
		{
			// Act
			XmlSchemaExtensions.GetEmbeddedSchema(null, "Test.xsd");
		}

		[Test]
		[ExpectedException(typeof (XmlSchemaValidationException))]
		public void ValidateXml_With_Invalid_Xml_ShouldThrow_XmlSchemaValidationException()
		{
			// Arrange
			var xml = new StringBuilder();
			xml.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
			xml.Append("<company />");

			var schemas = new XmlSchemaSet();
			schemas.Add(_executingAssembly.GetEmbeddedSchema("Company.xsd"));

			// Act
			xml.ToString().ValidateSchema(schemas);
		}

		[Test]
		[ExpectedException(typeof (XmlException))]
		public void ValidateXml_With_MissingRootElemenet_Xml_ShouldThrow_XmlSchemaValidationException()
		{
			// Arrange
			const string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

			var schemas = new XmlSchemaSet();
			schemas.Add(_executingAssembly.GetEmbeddedSchema("Company.xsd"));

			// Act
			xml.ValidateSchema(schemas);
		}

		[Test]
		public void ValidateXml_With_Valid_Xml_ShouldNotThrow_XmlSchemaValidationException()
		{
			// Arrange
			var company = GetCompany();

			var xml = company.SerializeXml();

			var schemas = new XmlSchemaSet();
			schemas.Add(_executingAssembly.GetEmbeddedSchema("Company.xsd"));

			// Act
			xml.ValidateSchema(schemas);
		}
	}
}